﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Windows.Forms;
using GMap.NET.WindowsForms;
using GMap.NET;
using GMap.NET.MapProviders;
using System.Diagnostics;
using System.Threading;
using System.IO;
using System.Xml;
using GMap.NET.WindowsForms.ToolTips;

namespace GMapTest
{
    public partial class MainForm : Form
    {
        GMapOverlay overlayOne;
        GMapOverlay overlayRoute;
        GMapMarker currentPosMarker;
        static TcpListener tcpListener;
        Thread listenThread;
        List<Thread> threadList = new List<Thread>();
        private  GMapMarker currentMarker;
       // Thread t;
        public MainForm()
        {
            InitializeComponent(); 
        }

        public void clientThread(object obj)
        {
            Socket soc = (Socket)obj;
            tcpClientMarker newMarker = new tcpClientMarker(overlayOne, Map1);
            try
            {
                
                Stream s = new NetworkStream(soc);
                StreamReader sr = new StreamReader(s);
                StreamWriter sw = new StreamWriter(s);
                sw.AutoFlush = true;
                newMarker = new tcpClientMarker(overlayOne, Map1);
                newMarker.ShowMarker();

                while (true)
                {
                    string test = sr.ReadLine();
                    newMarker.updatePosition(test);
                    sw.WriteLine("TEST do klienta!!");
                    if (test == "END!") break;
                }
                s.Close();
                newMarker.DeleteMarker();
                Debug.WriteLine("Disconnected: {0}", soc.RemoteEndPoint);
                soc.Close();
            }
            catch 
            {
                newMarker.DeleteMarker();
                soc.Close();
            }
        }

        public void listenerThread()
        {
            while (true)
            {
                try
                {
                Socket soc = tcpListener.AcceptSocket();
                Debug.WriteLine("Connected: {0}", soc.RemoteEndPoint);
                Thread client = new Thread(clientThread);
                client.Start(soc);
                threadList.Add(client);
                }
                catch (Exception e)
                {
                    Debug.WriteLine("An exception!: {0}", e.Message);
                    //newMarker.DeleteMarker();
                }
            }
        }

        public void calculateRouteThread()
        {
            RoutingProvider rp = Map1.MapProvider as RoutingProvider;
            if (rp == null)
                rp = GMapProviders.OpenStreetMap;
            MapRoute route = rp.GetRouteBetweenPoints(currentMarker.Position, currentPosMarker.Position, false, false, (int)Map1.Zoom);
            if (route != null)
            {
                GMapRoute r = new GMapRoute(route.Points, route.Name);
                overlayRoute.Routes.Clear();
                overlayRoute.Routes.Add(r);
                //Bardzo bardzo brzydki hack na wielowątkowe ustawianie tekstu w toolstripie ;/ 
                StatusLabel1.Text = "Ready";
                SelPos.Text = "Route selected. Distance: " + Math.Round(r.Distance, 2) + "km";
                try
                {

                }
                catch { }
            }
           // return 0;
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            Map1.SetCurrentPositionByKeywords("Poland");
            Map1.MapProvider = GMapProviders.OpenStreetMap;
            Map1.Zoom = 5;
            Map1.Manager.Mode = AccessMode.ServerAndCache;
            
            mapSelect.ValueMember = "Name";
            mapSelect.DataSource = GMapProviders.List;
            mapSelect.SelectedItem = Map1.MapProvider;

            overlayOne = new GMapOverlay(Map1, "OverlayOne");
            overlayRoute = new GMapOverlay(Map1, "OverlayRoute");
            currentPosMarker = new GMap.NET.WindowsForms.Markers.GMapMarkerGoogleGreen(new PointLatLng(36.657403, 10.327148));
            overlayOne.Markers.Add(currentPosMarker);

            Map1.Overlays.Add(overlayOne);
            Map1.Overlays.Add(overlayRoute);

            tcpListener = new TcpListener(IPAddress.Any, 2055);
            tcpListener.Start();
            Debug.WriteLine("Starting thread!");
            listenThread = new Thread(new ThreadStart(listenerThread));
            listenThread.Start();
            /*for (int i = 0; i < 1; i++)
            {
                Thread t2 = new Thread(new ThreadStart(listenerThread));
                t2.Start();
                threadList.Add(t2);
            }*/
        }

        private void mapSelect_SelectedValueChanged(object sender, EventArgs e)
        {
            //Map1.MapProvider = GMapProviders.List[mapSelect.SelectedIndex];
            //Map1.MapProvider = mapSelect.SelectedItem as GMapProvider;
        }

        private void mapSelect_DropDownClosed(object sender, EventArgs e)
        {
            Map1.MapProvider = mapSelect.SelectedItem as GMapProvider;
        }

        private void Map1_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                double Lat = Map1.FromLocalToLatLng(e.X, e.Y).Lat;
                double Lng = Map1.FromLocalToLatLng(e.X, e.Y).Lng;
                currentPosMarker.Position = new PointLatLng(Lat, Lng);
                SelPos.Text = String.Format("Lat:{0} Lng:{1}", Lat, Lng);
            }

            if(e.Button == MouseButtons.Left)
            {
                if(currentMarker != null && currentMarker.IsMouseOver)
                {
                    Thread calculateRoute = new Thread(new ThreadStart(calculateRouteThread));
                    StatusLabel1.Text = "Calculating...";
                    calculateRoute.Start();
                }
            }
        }

        private void Map1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            double Lat = Map1.FromLocalToLatLng(e.X, e.Y).Lat;
            double Lng = Map1.FromLocalToLatLng(e.X, e.Y).Lng;
            Map1.Position = new PointLatLng(Lat, Lng);
            Map1.Zoom = ((int)Map1.Zoom) + 1;
        }

        private void SearchLocationButton_Click(object sender, EventArgs e)
        {
            GeoCoderStatusCode status = GeoCoderStatusCode.Unknow;

            GeocodingProvider gp = Map1.MapProvider as GeocodingProvider;
            if (gp == null)
            {
                gp = GMapProviders.OpenStreetMap as GeocodingProvider;
            }

            if (gp != null)
            {
                var pt = gp.GetPoint(SearchLocationEdit.Text, out status);
                if (status == GeoCoderStatusCode.G_GEO_SUCCESS && pt.HasValue)
                {
                    Map1.Position = pt.Value;
                    currentPosMarker.Position = pt.Value;
                    StatusLabel1.Text = "Found!";
                    SelPos.Text = String.Format("Lat:{0} Lng:{1}", pt.Value.Lat, pt.Value.Lng);
                }
            }

            if (status != GeoCoderStatusCode.G_GEO_SUCCESS)
            {
                StatusLabel1.Text = SearchLocationEdit.Text + " not found!";
            }
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            tcpListener.Stop();
            listenThread.Abort();
            foreach (Thread item in threadList)
            {
                item.Abort();
            }
        }

        private void tableLayoutPanel1_Paint(object sender, PaintEventArgs e)
        {

        }

        private void trackBar1_ValueChanged(object sender, EventArgs e)
        {
           Map1.Zoom = ZoomBar.Value / 100.0;
        }

        private void ZoomInBtn_Click(object sender, EventArgs e)
        {
            if(Map1.Zoom<Map1.MaxZoom)
                Map1.Zoom += 1;
        }

        private void ZoomOutBtn_Click(object sender, EventArgs e)
        {
            if (Map1.Zoom > Map1.MinZoom)
                Map1.Zoom -= 1;
        }

        private void Map1_OnMarkerEnter(GMapMarker item)
        {
            currentMarker = item;
        }

        private void clearRoutesBtn_Click(object sender, EventArgs e)
        {
            overlayRoute.Routes.Clear();
        }

        private void saveImageBtn_Click(object sender, EventArgs e)
        {
            try
            {
                using (SaveFileDialog sfd = new SaveFileDialog())
                {
                    sfd.Filter = "PNG (*.png)|*.png";
                    sfd.FileName = "GMap.NET image";

                    Image tmpImage = Map1.ToImage();
                    if (tmpImage != null)
                    {
                        using (tmpImage)
                        {
                            if (sfd.ShowDialog() == DialogResult.OK)
                            {
                                tmpImage.Save(sfd.FileName);

                                MessageBox.Show("Image saved: " + sfd.FileName, "GMap.NET", MessageBoxButtons.OK, MessageBoxIcon.Information);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Image failed to save: " + ex.Message, "GMap.NET", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }


    }

    public class tcpClientMarker
    {
        GMapMarker PosMarker;
        GMapOverlay mapOverlay;
        GMapControl mapControl;

        string deviceId;

        public string DeviceId
        {
            get { return deviceId; }
            set { deviceId = value; }
        }
        double longtitude;

        public double Longtitude
        {
            get { return longtitude; }
            set { longtitude = value; }
        }
        double latitude;

        public double Latitude
        {
            get { return latitude; }
            set { latitude = value; }
        }

        public tcpClientMarker()
        {
        }

        public tcpClientMarker(GMapOverlay overlay, GMapControl control)
        {
            PosMarker = new GMap.NET.WindowsForms.Markers.GMapMarkerGoogleRed(new PointLatLng(53.0412130407565, 16.9189453125));
            PosMarker.ToolTip = new GMapBaloonToolTip(PosMarker);
            latitude = 0.0;
            longtitude = 0.0;
            deviceId = "";
            PosMarker.ToolTipText = "TEST";
            mapOverlay = overlay;
            mapControl = control;
        }

        public void ShowMarker()
        {
            mapOverlay.Markers.Add(PosMarker);
        }

        public void DeleteMarker()
        {
            if(mapOverlay!=null)
                mapOverlay.Markers.Remove(PosMarker);
        }

        public void updatePosition(string xml)
        {
            XmlDocument positionXml = new XmlDocument();
            positionXml.LoadXml(xml);
            XmlNode mobileReport = positionXml.SelectSingleNode("/MobilePositionReport");
            this.deviceId = positionXml.SelectSingleNode("/MobilePositionReport/DeviceID").LastChild.InnerText;
            Double.TryParse(positionXml.SelectSingleNode("/MobilePositionReport/Longtitude").LastChild.InnerText,out this.longtitude);
            Double.TryParse(positionXml.SelectSingleNode("/MobilePositionReport/Latitude").LastChild.InnerText, out this.latitude);
            PosMarker.Position = new PointLatLng(this.latitude, this.longtitude);
            PosMarker.ToolTipText = createTooltip();
        }

        string createTooltip()
        {
            //TODO napisać to porządnie!!
            Double distance = Math.Round(mapControl.MapProvider.Projection.GetDistance(mapControl.Overlays[0].Markers[0].Position,PosMarker.Position),3);
            String tooltip = "ID:" + this.DeviceId+"\n";
            tooltip += "Lat:"+this.Latitude+"\n";
            tooltip += "Lon:" + this.Longtitude + "\n";
            tooltip += "Dist:" + distance +"km";
            return tooltip;
        }
    }
}
